// for MS only
$$.XML = (function(){
	
	// 不完全JSON，某些XMLDoc的成员未依附其中。
	function parseXMLNode(node) {
		var obj = {};
		var element = node.firstChild;
		while (element) {
			if (element.nodeType === 1) {
				var name = element.nodeName;
				var sub = parseXMLNode(element)
				sub.nodeValue = "";
				sub.xml = element.xml;
				sub.toString = function() {
					return this.nodeValue;
				};
				sub.toXMLString = function() {
					return this.xml;
				}
				// get attributes
				if (element.attributes) {
					for (var i = 0; i < element.attributes.length; i++) {
						var attribute = element.attributes[i];
						sub[attribute.nodeName] = attribute.nodeValue;
					}
				}
				// get nodeValue
				if (element.firstChild) {
					var nodeType = element.firstChild.nodeType;
					if (nodeType === 3 || nodeType === 4) {
						sub.nodeValue = element.firstChild.nodeValue;
					}
				}
				// node already exists?
				if (obj[name]) {
					// need to create array?
					if (!obj[name].length) {
						var temp = obj[name];
						obj[name] = [];
						obj[name].push(temp);
					}
					// append object to array
					obj[name].push(sub);
				} else {
					// create object
					obj[name] = sub;
				}
			}
			element = element.nextSibling;
		}
		return obj;
	}

	var Xml = {
		text: function(text) {
			return (text != null) ? text.toString().replace(/\&/g, "&amp;").replace(/\</g, "&lt;").replace(/\>/g, "&gt;") : "";
		},
	
		attr: function(name, value) {
			return (name && value != null) ? (" " + name + "=\"" + this.text(value).replace(/\x22/g, "&quot;") + "\"") : "";
		},
	
		cdata: function(text) {
			return (text) ? ("<![CD" + "ATA[") + text.toString().replace(("]>" +">"), "]&gt;&gt;") + ("]>" + ">") : "";
		},
	
		comment: function(text) {
			return (text) ? "<!-" + "-" + text.toString().replace("--", "\x2D\x2D") + "-->" : "";
		},
	
	 
		toXMLString: function(obj){
			var xml = [];
			function serialize(obj) {
				var xml = [];
				var type = typeof obj;
				switch (type) {
					case "object" : {
						if (obj === null) {
							xml.push("<"+i+" />\n");
						} else if (typeof obj.getTime === "function") {
							xml.push("<"+i+Xml.attr("type", "date")+(obj !== "" ? ">"+obj.toUTCString()+"</"+i : " /")+">\n");
						} else if (typeof obj.join === "function") {
							for (var j=0; j<obj.length; j++) {
								xml.push(serialize(obj[j]));
							}
						} else {
							var sub = Xml.toXMLString(obj);
							xml.push("<"+i+Xml.attr("type", type)+(sub !== "" ? ">\n"+sub+"</"+i : " /")+">\n");
						}
						break;
					}
					case "string" :
						xml.push("<"+i+Xml.attr("type", type)+(obj !== "" ? ">"+Xml.text(obj)+"</"+i : " /")+">\n");
						break;
					case "date" :
					case "boolean" :
					case "number" : {
						xml.push("<"+i+Xml.attr("type", type)+">"+obj+"</"+i+">\n");
						break;
					}
				}
				return xml.join("");
			}
			for (var i in obj) {
				xml.push(serialize(obj[i]));
			}
			return xml.join("");
		}
	};

	return {
		
		/**
		 * 把XML格式转换为JSON输出。
		 * @param {IXMLDOMNode} n
		 * @return {Object} JSON
		 */
		 parse: parseXMLNode

		,json2xml: Xml.toXMLString
		
		/**
		 * 保存XML对象为XML文本文件。
		 * 注意：Server Side Only
		 * @param {XMLDocument} xmlDoc XML文档对象本身。
		 * @param {String} xmlFilePath 可选的。XML文档的真实磁盘路径。
		 * @return {Boolean} 是否操作成功。
		 */
		,saveXML: function(xmlDoc, xmlFilePath){
		 	xmlFilePath = xmlFilePath || xmlDoc.url.replace(/file:\/\/\//,'');
		 	// make a clone
			var	saver = new ActiveXObject('Msxml2.DOMDocument.6.0');
				saver.loadXML(xmlDoc.xml);
				
			if(	saver.readyState == 4 && saver.parsed){
				saver.save(xmlFilePath);
			}
			
			return true;
		}
		
		/**
		 * 依据数据值是什么（在data里查找匹配的），决定选中哪一个Option控件。
		 * @param {IXMLDOMNode} n XML节点对象。
		 * @param {Object} data 数据对象。
		 * @return {IXMLDOMNode} XML节点对象。
		 */
		,setSelectByNode: function(n, data){
            var i, k;
            var selectEl;
            
            for(i in data){
                k = ".//select[@name='{0}']".format(i);
                selectEl = n.selectSingleNode(k);
                if(selectEl){
                    // 选中value一样的节点
                    for(var z = 0; z < 2; z++){
                        if( selectEl.childNodes(z).attributes(0).value == data[i]){
                            selectEl.childNodes(z).setAttribute('selected', 'true'); // 设置为选中！
                        } 
                    }
                }
            }
            return n;
		}
		
		/**
		 * 依据数据值是什么（在data里查找匹配的），决定选中哪一个Radio控件。
		 * @param {IXMLDOMNode} n XML节点对象。
		 * @param {Object} data 数据对象。
		 * @return {IXMLDOMNode} XML节点对象。
		 */
		,setRadioByNode: function(n, data){
            var i, k;
            var selectEl;
            
            for(i in data){
                k = ".//input[@name='{0}']".format(i);
                
                selectEl = n.selectNodes(k);
                if(selectEl && selectEl.length > 0){
                    // 选中value一样的节点
                    for(var z = 0; z < selectEl.length; z++){
                    	// 默认attributes(3)是name属性
                        if( selectEl(z).attributes(1).value == data[i]){
                            selectEl(z).setAttribute('checked', 'true'); // 设置为选中！
                        } 
                    }
                }
            }
            return n;
		}
		
		/**
		 * 从XML文档中选择指定的模板文件，将其数据绑定data输出。
		 * 有取消CData作转意之功能。
		 * @param {String} xmlFile XML片段或者是XML文件，需要完全的文件路径地址，一般需要Server.Mappath获取真实地址后才输入到这里。
		 * @param {String} xPath XPath路径。
		 * @param {Object} data （可选的）数据实体，通常是JSON实体或者是配置文件$$.cfg。
		 * @return {String} 携带数据的HTML。
		 */
		,from_XML_Tpl : function(node, data){
			var  
				 tpl
				,html;
			
			if(data){
				// Option的Selected属性等的居然没用完整XML陈述形式！！
				$$.XML.setSelectByNode(node, data);
				$$.XML.setRadioByNode(node,  data);
			}
	   		 tpl  = node.xml
	   		,tpl  = tpl.replace('&amp;', '&') // 规避XML标准的转义
	   		,html = data ? new $$.Template(tpl, data).html : tpl;
	   		
   			// 由于有些地步不合XML WellForm标准，故用CData豁免之，先还原。
	   		if(html.indexOf('<![CD' + 'ATA[')){ 
	   			html = html.replace('<![CDA' + 'TA[', '').replace(']' + ']>', '');
	   		}
	   		return html;
		}
	};
})();